/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sensorfriendly.ui;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.text.Layout;
import android.util.AttributeSet;
import android.widget.TextView;

/**
 * TextView that draws a bubble behind the text. We cannot use a
 * LineBackgroundSpan because we want to make the bubble taller than the text
 * and TextView's clip is too aggressive.
 */
public class BubbleTextView extends TextView {
	private static final float CORNER_RADIUS = 8.0f;
	private static final float PADDING_H = 5.0f;
	private static final float PADDING_V = 1.0f;
	private static final int DELAY_DEFAULT = 250;
	
	private final RectF mRect = new RectF();
	private Paint mPaint;

	private boolean mBackgroundSizeChanged;
	private Drawable mBackground;
	private float mCornerRadius;
	private float mPaddingH;
	private float mPaddingV;

	private CharSequence mText;
	private int mIndex;
	private long mDelay = DELAY_DEFAULT; // Default 500ms delay
	private String[] words;

	public BubbleTextView(Context context) {
		super(context);
		init();
	}

	public BubbleTextView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}

	private void init() {
		setFocusable(true);
		mBackground = getBackground();
		setBackgroundDrawable(null);
		mBackground.setCallback(this);

		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPaint.setColor(getContext().getResources().getColor(
				android.R.color.background_light));

		final float scale = getContext().getResources().getDisplayMetrics().density;
		mCornerRadius = CORNER_RADIUS * scale;
		mPaddingH = PADDING_H * scale;
		// noinspection PointlessArithmeticExpression
		mPaddingV = PADDING_V * scale;
	}

	@Override
	protected boolean setFrame(int left, int top, int right, int bottom) {
		if (getLeft() != left || getRight() != right || getTop() != top
				|| getBottom() != bottom) {
			mBackgroundSizeChanged = true;
		}
		return super.setFrame(left, top, right, bottom);
	}

	@Override
	protected boolean verifyDrawable(Drawable who) {
		return who == mBackground || super.verifyDrawable(who);
	}

	@Override
	protected void drawableStateChanged() {
		Drawable d = mBackground;
		if (d != null && d.isStateful()) {
			d.setState(getDrawableState());
		}
		super.drawableStateChanged();
	}

	@Override
	public void draw(Canvas canvas) {
		final Drawable background = mBackground;
		if (background != null) {
			final int scrollX = getScrollX();
			final int scrollY = getScrollY();

			if (mBackgroundSizeChanged) {
				background.setBounds(0, 0, getRight() - getLeft(), getBottom()
						- getTop());
				mBackgroundSizeChanged = false;
			}

			if ((scrollX | scrollY) == 0) {
				background.draw(canvas);
			} else {
				canvas.translate(scrollX, scrollY);
				background.draw(canvas);
				canvas.translate(-scrollX, -scrollY);
			}
		}

		final Layout layout = getLayout();
		final RectF rect = mRect;
		final int left = getCompoundPaddingLeft();
		final int top = getExtendedPaddingTop();

		rect.set(left + layout.getLineLeft(0) - mPaddingH,
				top + layout.getLineTop(0) - mPaddingV, Math.min(
						left + layout.getLineRight(0) + mPaddingH, getScrollX()
								+ getRight() - getLeft()),
				top + layout.getLineBottom(0) + mPaddingV);
		canvas.drawRoundRect(rect, mCornerRadius, mCornerRadius, mPaint);

		super.draw(canvas);
	}

	private Handler mHandler = new Handler();
	/**
	 * Runnable that animates the textbox by adding a word to it after an interval.
	 */
	private Runnable characterAdder = new Runnable() {
		@Override
		public void run() {
			StringBuilder sb = new StringBuilder();
			mIndex++;
			for(int i=0; i<mIndex; i++){
				sb.append(words[i]+" ");
			}
			setText(sb.toString());
			long delay = mDelay;
			if (mIndex < words.length) {
				if(words[mIndex].contains(".") || words[mIndex].contains("?") || words[mIndex].contains(",") ){
					delay = delay + 150;
				}
				else{
					delay = mDelay;
				}
				mHandler.postDelayed(characterAdder, delay);
			}
		}
	};

	/**
	 * triggers the animatioin of text
	 * @param text the string that needs to be animated
	 */
	public void animateText(CharSequence text) {
		mText = text;
		words = text.toString().split(" ");
		mIndex = 0;
		setText("");
		mHandler.removeCallbacks(characterAdder);
		mDelay = DELAY_DEFAULT;
		mHandler.postDelayed(characterAdder, mDelay);
	}
	
	/**
	 * triggers the animatioin of text with the specify interval for adding each word.
	 * @param text text the string that needs to be animated
	 * @param duration animation interval
	 */
	public void animateText(CharSequence text, int duration) {
		mText = text;
		words = text.toString().split(" ");
		mIndex = 0;
		setText("");
		mHandler.removeCallbacks(characterAdder);
		mDelay = duration/words.length;
		mHandler.postDelayed(characterAdder, mDelay);
	}

	public void setCharacterDelay(long millis) {
		mDelay = millis;
	}
	
	public void stopAnimation(){
		mHandler.removeCallbacks(characterAdder);
		
	}
	
}